"""
Webhook服务类
使用反射机制处理Stripe webhook事件
"""

import stripe
import logging
import json
import hmac
import hashlib
from datetime import datetime
from typing import Dict, Any, Optional, Callable
from fastapi import HTTPException, Request

from utils.config import Config
from utils.data_store import DataStore
from models.webhook_models import WebhookEvent, WebhookResponse

logger = logging.getLogger(__name__)


class WebhookService:
    """Webhook服务类，使用反射机制处理Stripe事件"""

    def __init__(self, customer_service=None, product_service=None, subscription_service=None):
        self.customer_service = customer_service
        self.product_service = product_service
        self.subscription_service = subscription_service

        # Webhook配置
        self.endpoint_secret = Config.WEBHOOK_ENDPOINT_SECRET

        # 事件处理器映射
        self.event_handlers = {
            # 支付相关事件
            'payment_intent.succeeded': self.payment_intent_succeeded,
            'payment_intent.payment_failed': self.payment_failed,
            'payment_intent.canceled': self.payment_canceled,

            # 客户相关事件
            'customer.created': self.customer_created,
            'customer.updated': self.customer_updated,
            'customer.deleted': self.customer_deleted,

            # 订阅相关事件
            'customer.subscription.created': self.subscription_created,
            'customer.subscription.updated': self.subscription_updated,
            'customer.subscription.deleted': self.subscription_deleted,
            'customer.subscription.trial_will_end': self.subscription_trial_will_end,
            'subscription.payment_succeeded': self.subscription_payment_succeeded,
            'subscription.payment_failed': self.subscription_payment_failed,

            # 发票相关事件
            'invoice.payment_succeeded': self.invoice_payment_succeeded,
            'invoice.payment_failed': self.invoice_payment_failed,
            'invoice.created': self.invoice_created,
            'invoice.updated': self.invoice_updated,

            # 产品相关事件
            'product.created': self.product_created,
            'product.updated': self.product_updated,
            'product.deleted': self.product_deleted,

            # 价格相关事件
            'price.created': self.price_created,
            'price.updated': self.price_updated,
            'price.deleted': self.price_deleted,
        }

    async def process_webhook(self, request: Request, signature: str) -> WebhookResponse:
        """处理webhook请求"""
        try:
            # 读取请求体
            payload = await request.body()

            try:
                # 验证签名并解析事件
                # 第三个参数是 Webhook 密钥，第四个参数是时间戳容忍度（秒）
                event = stripe.Webhook.construct_event(
                    payload, signature, self.endpoint_secret, tolerance=300
                )
            except Exception as e:
                # 无效的 payload 格式
                return WebhookResponse(
                    status="failed",
                    message="验证签名失败",
                    event_type="",
                    event_id="",
                )

            # 解析事件
            event_type = event['type']
            event_id = event['id']
            created_time = event['created']  # 事件创建时间（Unix 时间戳）
            event_data = event['data']['object']

            logger.info(f"收到webhook事件: {event_type} (ID: {event_id})")

            # 使用反射机制查找并调用对应的处理方法
            handler_method = self._get_handler_method(event_type)

            if handler_method:
                # 调用对应的处理方法
                result = handler_method(event_data)
                processed = True
                message = f"事件 {event_type} 处理成功"
            else:
                # 没有找到对应的处理方法
                result = None
                processed = False
                message = f"未找到事件 {event_type} 的处理方法"
                logger.warning(f"未找到事件处理器: {event_type}")

            return WebhookResponse(
                status="success",
                message=message,
                event_id=event_id,
                event_type=event_type,
                event_created_time=created_time,
            )
        except Exception as e:
            logger.error(f"处理webhook失败: {e}")
            raise HTTPException(status_code=500, detail=f"处理webhook失败: {str(e)}")

    def _get_handler_method(self, event_type: str) -> Optional[Callable]:
        """使用反射机制获取事件处理方法"""
        # 将事件类型转换为方法名
        method_name = event_type.replace('.', '_')

        # 首先检查是否有预定义的处理器
        if event_type in self.event_handlers:
            return self.event_handlers[event_type]

        # 如果没有预定义处理器，尝试动态查找方法
        if hasattr(self, method_name):
            method = getattr(self, method_name)
            if callable(method):
                return method

        return None

    # ==================== 支付相关事件处理器 ====================

    def payment_intent_succeeded(self, payment_intent: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付成功事件"""
        logger.info(f"支付成功: {payment_intent['id']} - 金额: {payment_intent['amount']}")

        # 这里可以添加支付成功后的业务逻辑
        # 例如：更新订单状态、发送确认邮件等

        return {
            'payment_intent_id': payment_intent['id'],
            'amount': payment_intent['amount'],
            'currency': payment_intent['currency'],
            'status': payment_intent['status']
        }

    def payment_failed(self, payment_intent: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付失败事件"""
        logger.warning(f"支付失败: {payment_intent['id']}")

        # 这里可以添加支付失败后的业务逻辑
        # 例如：发送失败通知、重试机制等

        return {
            'payment_intent_id': payment_intent['id'],
            'status': payment_intent['status'],
            'last_payment_error': payment_intent.get('last_payment_error')
        }

    def payment_canceled(self, payment_intent: Dict[str, Any]) -> Dict[str, Any]:
        """处理支付取消事件"""
        logger.info(f"支付取消: {payment_intent['id']}")

        return {
            'payment_intent_id': payment_intent['id'],
            'status': payment_intent['status']
        }

    # ==================== 客户相关事件处理器 ====================

    def customer_created(self, customer: Dict[str, Any]) -> Dict[str, Any]:
        """处理客户创建事件"""
        logger.info(f"客户创建: {customer['id']} - {customer.get('email', 'N/A')}")

        # 更新本地客户数据
        if self.customer_service:
            self._update_local_customer(customer)

        return {
            'customer_id': customer['id'],
            'email': customer.get('email'),
            'name': customer.get('name')
        }

    def customer_updated(self, customer: Dict[str, Any]) -> Dict[str, Any]:
        """处理客户更新事件"""
        logger.info(f"客户更新: {customer['id']}")

        # 更新本地客户数据
        if self.customer_service:
            self._update_local_customer(customer)

        return {
            'customer_id': customer['id'],
            'email': customer.get('email'),
            'name': customer.get('name')
        }

    def customer_deleted(self, customer: Dict[str, Any]) -> Dict[str, Any]:
        """处理客户删除事件"""
        logger.info(f"客户删除: {customer['id']}")

        # 更新本地客户数据
        if self.customer_service:
            self._update_local_customer(customer)

        return {
            'customer_id': customer['id']
        }

    # ==================== 订阅相关事件处理器 ====================

    def subscription_created(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅创建事件"""
        logger.info(f"订阅创建: {subscription['id']} - 状态: {subscription['status']}")

        # 创建或更新本地订阅数据
        if self.subscription_service:
            self._create_or_update_local_subscription(subscription)
            # 确保数据更新后及时刷新到内存中
            self.subscription_service.reload_data()

        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'status': subscription['status'],
            'current_period_start': subscription['current_period_start'],
            'current_period_end': subscription['current_period_end']
        }

    def subscription_updated(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅更新事件"""
        logger.info(f"订阅更新: {subscription['id']} - 状态: {subscription['status']}")
        print(subscription)
        # 创建或更新本地订阅数据
        if self.subscription_service:
            self._create_or_update_local_subscription(subscription)
            # 确保数据更新后及时刷新到内存中
            self.subscription_service.reload_data()

        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'status': subscription['status'],
            'current_period_start': subscription['current_period_start'],
            'current_period_end': subscription['current_period_end']
        }

    def subscription_deleted(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅删除事件"""
        logger.info(f"订阅删除: {subscription['id']}")

        # 更新本地订阅数据
        if self.subscription_service:
            self._update_local_subscription(subscription)
            # 确保数据更新后及时刷新到内存中
            self.subscription_service.reload_data()

        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'status': subscription['status']
        }

    def subscription_trial_will_end(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅试用期即将结束事件"""
        logger.info(f"订阅试用期即将结束: {subscription['id']}")
        
        # 这里可以添加试用期即将结束的业务逻辑
        # 例如：发送提醒邮件、显示升级提示等
        
        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'trial_end': subscription.get('trial_end')
        }
    
    def subscription_payment_succeeded(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅支付成功事件"""
        logger.info(f"订阅支付成功: {subscription['id']}")
        
        # 创建或更新本地订阅数据
        if self.subscription_service:
            self._create_or_update_local_subscription(subscription)
            # 确保数据更新后及时刷新到内存中
            self.subscription_service.reload_data()
        
        # 这里可以添加支付成功后的业务逻辑
        # 例如：更新订单状态、发送确认邮件、激活服务等
        
        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'status': subscription['status'],
            'current_period_start': subscription.get('current_period_start'),
            'current_period_end': subscription.get('current_period_end'),
            'latest_invoice': subscription.get('latest_invoice')
        }
    
    def subscription_payment_failed(self, subscription: Dict[str, Any]) -> Dict[str, Any]:
        """处理订阅支付失败事件"""
        logger.warning(f"订阅支付失败: {subscription['id']}")
        
        # 创建或更新本地订阅数据
        if self.subscription_service:
            self._create_or_update_local_subscription(subscription)
            # 确保数据更新后及时刷新到内存中
            self.subscription_service.reload_data()
        
        # 这里可以添加支付失败后的业务逻辑
        # 例如：发送失败通知、暂停服务、重试机制等
        
        return {
            'subscription_id': subscription['id'],
            'customer_id': subscription['customer'],
            'status': subscription['status'],
            'latest_invoice': subscription.get('latest_invoice'),
            'next_payment_attempt': subscription.get('next_payment_attempt')
        }

    # ==================== 发票相关事件处理器 ====================

    def invoice_payment_succeeded(self, invoice: Dict[str, Any]) -> Dict[str, Any]:
        """处理发票支付成功事件"""
        logger.info(f"发票支付成功: {invoice['id']}")

        return {
            'invoice_id': invoice['id'],
            'subscription_id': invoice.get('subscription'),
            'amount_paid': invoice['amount_paid'],
            'status': invoice['status']
        }

    def invoice_payment_failed(self, invoice: Dict[str, Any]) -> Dict[str, Any]:
        """处理发票支付失败事件"""
        logger.warning(f"发票支付失败: {invoice['id']}")

        return {
            'invoice_id': invoice['id'],
            'subscription_id': invoice.get('subscription'),
            'amount_due': invoice['amount_due'],
            'status': invoice['status']
        }

    def invoice_created(self, invoice: Dict[str, Any]) -> Dict[str, Any]:
        """处理发票创建事件"""
        logger.info(f"发票创建: {invoice['id']}")

        return {
            'invoice_id': invoice['id'],
            'subscription_id': invoice.get('subscription'),
            'amount_due': invoice['amount_due'],
            'status': invoice['status']
        }

    def invoice_updated(self, invoice: Dict[str, Any]) -> Dict[str, Any]:
        """处理发票更新事件"""
        logger.info(f"发票更新: {invoice['id']}")

        return {
            'invoice_id': invoice['id'],
            'subscription_id': invoice.get('subscription'),
            'amount_due': invoice['amount_due'],
            'status': invoice['status']
        }

    # ==================== 产品相关事件处理器 ====================

    def product_created(self, product: Dict[str, Any]) -> Dict[str, Any]:
        """处理产品创建事件"""
        logger.info(f"产品创建: {product['id']} - 产品: {product.get('name', 'N/A')}")

        # 更新本地产品数据
        if self.product_service:
            self._update_local_product(product)

        return {
            'product_id': product['id'],
            'name': product.get('name'),
            'description': product.get('description')
        }

    def product_updated(self, product: Dict[str, Any]) -> Dict[str, Any]:
        """处理产品更新事件"""
        logger.info(f"产品更新: {product['id']}")

        # 更新本地产品数据
        if self.product_service:
            self._update_local_product(product)

        return {
            'product_id': product['id'],
            'name': product.get('name'),
            'description': product.get('description')
        }

    def product_deleted(self, product: Dict[str, Any]) -> Dict[str, Any]:
        """处理产品删除事件"""
        logger.info(f"产品删除: {product['id']}")

        # 更新本地产品数据
        if self.product_service:
            self._update_local_product(product)

        return {
            'product_id': product['id']
        }

    # ==================== 价格相关事件处理器 ====================

    def price_created(self, price: Dict[str, Any]) -> Dict[str, Any]:
        """处理价格创建事件"""
        logger.info(f"价格创建: {price['id']} - 产品: {price.get('product', 'N/A')}")

        return {
            'price_id': price['id'],
            'product_id': price.get('product'),
            'unit_amount': price.get('unit_amount'),
            'currency': price.get('currency')
        }

    def price_updated(self, price: Dict[str, Any]) -> Dict[str, Any]:
        """处理价格更新事件"""
        logger.info(f"价格更新: {price['id']}")

        return {
            'price_id': price['id'],
            'product_id': price.get('product'),
            'unit_amount': price.get('unit_amount'),
            'currency': price.get('currency')
        }

    def price_deleted(self, price: Dict[str, Any]) -> Dict[str, Any]:
        """处理价格删除事件"""
        logger.info(f"价格删除: {price['id']}")

        return {
            'price_id': price['id'],
            'product_id': price.get('product')
        }

    # ==================== 辅助方法 ====================

    def _create_or_update_local_subscription(self, stripe_subscription: Dict[str, Any]):
        """创建或更新本地订阅数据"""
        try:
            # 在更新之前先重新加载数据，确保对最新数据进行更新
            self.subscription_service.reload_data()
            
            # 查找对应的本地订阅记录
            existing_subscription_id = None
            for sub_id, sub_data in self.subscription_service.subscriptions.items():
                if sub_data.get('stripe_subscription_id') == stripe_subscription['id']:
                    existing_subscription_id = sub_id
                    break
            
            if existing_subscription_id:
                # 更新现有订阅记录
                sub_data = self.subscription_service.subscriptions[existing_subscription_id]
                sub_data['status'] = stripe_subscription['status']
                sub_data['current_period_start'] = stripe_subscription['current_period_start']
                sub_data['current_period_end'] = stripe_subscription['current_period_end']
                sub_data['cancel_at_period_end'] = stripe_subscription['cancel_at_period_end']
                sub_data['updated_at'] = datetime.now().isoformat()
                
                logger.info(f"本地订阅数据已更新: {existing_subscription_id}")
            else:
                # 创建新的订阅记录
                import uuid
                new_subscription_id = str(uuid.uuid4())
                
                # 从Stripe订阅中提取产品信息
                product_id = None
                if stripe_subscription.get('items') and stripe_subscription['items'].get('data'):
                    # 获取第一个订阅项目
                    first_item = stripe_subscription['items']['data'][0]
                    if first_item.get('price') and first_item['price'].get('product'):
                        product_id = first_item['price']['product']
                
                # 构建新的订阅数据
                new_subscription_data = {
                    'id': new_subscription_id,
                    'stripe_subscription_id': stripe_subscription['id'],
                    'customer_id': stripe_subscription['customer'],
                    'product_id': product_id,
                    'status': stripe_subscription['status'],
                    'current_period_start': stripe_subscription['current_period_start'],
                    'current_period_end': stripe_subscription['current_period_end'],
                    'cancel_at_period_end': stripe_subscription['cancel_at_period_end'],
                    'metadata': stripe_subscription.get('metadata', {}),
                    'created_at': datetime.now().isoformat(),
                    'updated_at': datetime.now().isoformat()
                }
                
                self.subscription_service.subscriptions[new_subscription_id] = new_subscription_data
                logger.info(f"本地订阅数据已创建: {new_subscription_id}")

            # 保存到本地存储
            DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscription_service.subscriptions)
            
            # 更新后再次重新加载数据，确保内存中的数据是最新的
            self.subscription_service.reload_data()
            
        except Exception as e:
            logger.error(f"创建或更新本地订阅数据失败: {e}")

    def _update_local_subscription(self, stripe_subscription: Dict[str, Any]):
        """更新本地订阅数据"""
        try:
            # 在更新之前先重新加载数据，确保对最新数据进行更新
            self.subscription_service.reload_data()
            
            # 查找对应的本地订阅记录
            for sub_id, sub_data in self.subscription_service.subscriptions.items():
                if sub_data.get('stripe_subscription_id') == stripe_subscription['id']:
                    # 更新订阅状态
                    sub_data['status'] = stripe_subscription['status']
                    sub_data['current_period_start'] = stripe_subscription['current_period_start']
                    sub_data['current_period_end'] = stripe_subscription['current_period_end']
                    sub_data['cancel_at_period_end'] = stripe_subscription['cancel_at_period_end']
                    sub_data['updated_at'] = datetime.now().isoformat()

                    # 保存到本地存储
                    DataStore.save_data(Config.SUBSCRIPTIONS_FILE, self.subscription_service.subscriptions)
                    logger.info(f"本地订阅数据已更新: {sub_id}")
                    
                    # 更新后再次重新加载数据，确保内存中的数据是最新的
                    self.subscription_service.reload_data()
                    break
        except Exception as e:
            logger.error(f"更新本地订阅数据失败: {e}")

    def _update_local_customer(self, stripe_customer: Dict[str, Any]):
        """更新本地客户数据"""
        try:
            # 在更新之前先重新加载数据，确保对最新数据进行更新
            self.customer_service.reload_data()
            
            # 查找对应的本地客户记录
            for cust_id, cust_data in self.customer_service.customers.items():
                if cust_data.get('stripe_customer_id') == stripe_customer['id']:
                    # 更新客户信息
                    cust_data['email'] = stripe_customer.get('email')
                    cust_data['name'] = stripe_customer.get('name')
                    cust_data['updated_at'] = datetime.now().isoformat()

                    # 保存到本地存储
                    DataStore.save_data(Config.CUSTOMERS_FILE, self.customer_service.customers)
                    logger.info(f"本地客户数据已更新: {cust_id}")
                    
                    # 更新后再次重新加载数据，确保内存中的数据是最新的
                    self.customer_service.reload_data()
                    break
        except Exception as e:
            logger.error(f"更新本地客户数据失败: {e}")

    def _update_local_product(self, stripe_product: Dict[str, Any]):
        """更新本地产品数据"""
        try:
            # 在更新之前先重新加载数据，确保对最新数据进行更新
            self.product_service.reload_data()
            
            # 查找对应的本地产品记录
            for prod_id, prod_data in self.product_service.products.items():
                if prod_data.get('stripe_product_id') == stripe_product['id']:
                    # 更新产品信息
                    prod_data['name'] = stripe_product.get('name')
                    prod_data['description'] = stripe_product.get('description')
                    prod_data['updated_at'] = datetime.now().isoformat()

                    # 保存到本地存储
                    DataStore.save_data(Config.PRODUCTS_FILE, self.product_service.products)
                    logger.info(f"本地产品数据已更新: {prod_id}")
                    
                    # 更新后再次重新加载数据，确保内存中的数据是最新的
                    self.product_service.reload_data()
                    break
        except Exception as e:
            logger.error(f"更新本地产品数据失败: {e}")

    def get_supported_events(self) -> list[str]:
        """获取支持的事件类型列表"""
        return list(self.event_handlers.keys())

    def add_custom_handler(self, event_type: str, handler_method: Callable):
        """添加自定义事件处理器"""
        self.event_handlers[event_type] = handler_method
        logger.info(f"添加自定义事件处理器: {event_type}")

    def remove_handler(self, event_type: str):
        """移除事件处理器"""
        if event_type in self.event_handlers:
            del self.event_handlers[event_type]
            logger.info(f"移除事件处理器: {event_type}")

    def get_handler_info(self) -> Dict[str, str]:
        """获取所有事件处理器的信息"""
        return {
            event_type: handler.__name__
            for event_type, handler in self.event_handlers.items()
        }
